/*
 * HudButton.fx
 */

package org.frapwidgets.scene.control.hud;

import javafx.geometry.HPos;
import javafx.geometry.VPos;
import javafx.scene.Node;
import javafx.scene.control.Behavior;
import javafx.scene.control.Control;
import javafx.scene.control.Label;
import javafx.scene.control.Labeled;
import javafx.scene.control.Skin;
import javafx.scene.layout.Container;
import javafx.scene.layout.Stack;
import javafx.scene.paint.Color;
import javafx.scene.paint.LinearGradient;
import javafx.scene.paint.Stop;
import javafx.scene.text.Font;
import javafx.scene.text.FontWeight;

import org.frapwidgets.scene.shape.hud.HudButtonRectangle;


/**
 * A HUD button.
 *
 * @author Jonathan Merritt
 */
public class HudButton extends Control, Labeled {
  // button properties
  public var action: function():Void;
  public var strong: Boolean = false;
  public-init var arcDiam: Number = 17;

  // default labeled properties
  override public var font = Font.font("sans", FontWeight.EXTRA_BOLD, 10);
  override public var hpos = HPos.CENTER;
  override public var vpos = VPos.CENTER;

  override function create(): Node {
    skin = HudButtonSkin {
      arcDiam: arcDiam
    };
    super.create();
  }
}


public class HudButtonSkin extends Skin {
  public var buttonControl = bind control as HudButton;
  override var behavior = HudButtonBehavior{}

  public-init var arcDiam: Number;

  var upRect: HudButtonRectangle;
  var dnRect: HudButtonRectangle;
  def label = Label {
    font: bind buttonControl.font
    graphic: bind buttonControl.graphic
    graphicHPos: bind buttonControl.graphicHPos
    graphicTextGap: bind buttonControl.graphicTextGap
    graphicVPos: bind buttonControl.graphicVPos
    hpos: bind buttonControl.hpos
    text: bind buttonControl.text
    textAlignment: bind buttonControl.textAlignment
    textOverrun: bind buttonControl.textOverrun
    textWrap: bind buttonControl.textWrap
    vpos: bind buttonControl.vpos
    textFill: Color.WHITE
  }
  
  def boundStrong = bind buttonControl.strong on replace {
    setButtonStates();
  }
  def boundDisabled = bind buttonControl.disabled on replace {
    setButtonStates();
  }
  def pressed = bind buttonControl.pressed and buttonControl.hover on replace {
    // set visibility of button rectangles; depending upon whether the button
    //  is pressed or not
    upRect.visible = not pressed;
    dnRect.visible = pressed;

    // a button click occurs when the mouse is no longer pressed, yet the
    //  pointer is still hovering over the button
    if ((not buttonControl.pressed) and buttonControl.hover) {
      (behavior as HudButtonBehavior).buttonPressed();
    }
  }

  function setButtonStates() {
    var edgePaintUp: LinearGradient;
    var fillPaintUp: LinearGradient;
    var edgePaintDn: LinearGradient;
    var fillPaintDn: LinearGradient;

    if (buttonControl.disabled) {
      edgePaintUp = outerUpGradDisabled;
      fillPaintUp = innerUpGradDisabled;
      edgePaintDn = fillPaintDn = null;
    } else {
      if (buttonControl.strong) {
        edgePaintUp = outerUpGradStrong;
        fillPaintUp = innerUpGradStrong;
        edgePaintDn = outerDnGradStrong;
        fillPaintDn = innerDnGradStrong;
      } else {
        edgePaintUp = outerUpGradNormal;
        fillPaintUp = innerUpGradNormal;
        edgePaintDn = outerDnGradNormal;
        fillPaintDn = innerDnGradNormal;
      }
    }

    upRect = HudButtonRectangle {
      arcDiam: arcDiam
      edgePaint: edgePaintUp
      fillPaint: fillPaintUp
      visible: not buttonControl.pressed
      cache: true
    }
    dnRect = HudButtonRectangle {
      arcDiam: arcDiam
      edgePaint: edgePaintDn
      fillPaint: fillPaintDn
      visible: buttonControl.pressed
      cache: true
    }

    if (buttonControl.disabled) {
      label.textFill = Color.color(0.6, 0.6, 0.6);
    } else {
      label.textFill = Color.WHITE;
    }

    btnNode.content = [ upRect, dnRect, label ];
  }

  def btnNode = Stack {
    width: bind buttonControl.width;
    height: bind buttonControl.height;
  }

  init {
    node = btnNode
  }

  override function getPrefHeight(width: Number): Number {
    17;
  }

  override function getMinHeight(): Number {
    getPrefHeight(0);
  }

  override function getPrefWidth(height: Number): Number {
    Container.getNodePrefWidth(label) + 35;
  }

  override function getMinWidth(): Number {
    Container.getNodePrefWidth(label);
  }

  override function contains(localX: Number, localY: Number): Boolean {
    node.contains(localX, localY)
  }

  override function intersects(
    localX: Number,
    localY: Number,
    localWidth: Number,
    localHeight: Number
  ): Boolean {
    node.intersects(localX, localY, localWidth, localHeight)
  }

}


public class HudButtonBehavior extends Behavior {
  public function buttonPressed(): Void {
    (skin.control as HudButton).action();
  }
}


// up normal
def outerUpGradNormal = createGrayVGrad(0.57, 0.25);
def innerUpGradNormal = createGrayVGrad(0.36, 0.22);
// down normal
def outerDnGradNormal = createGrayVGrad(0.42, 0.38);
def innerDnGradNormal = createGrayVGrad(0.31, 0.36);
// up strong
def outerUpGradStrong = createColorVGrad(
  Color.color(0.33, 0.54, 0.92), Color.color(0.14, 0.25, 0.44));
def innerUpGradStrong = createColorVGrad(
  Color.color(0.21, 0.35, 0.62), Color.color(0.13, 0.22, 0.40));
// down strong
def outerDnGradStrong = createColorVGrad(
  Color.color(0.25, 0.42, 0.69), Color.color(0.23, 0.38, 0.62));
def innerDnGradStrong = createColorVGrad(
  Color.color(0.19, 0.32, 0.51), Color.color(0.22, 0.37, 0.60));
// up disabled
def outerUpGradDisabled = createGrayVGrad(0.50, 0.40);
def innerUpGradDisabled = createGrayVGrad(0.45, 0.40);

function createColorVGrad(top: Color, bottom: Color): LinearGradient {
  LinearGradient {
    endX: 0, proportional: true
    stops: [ Stop { color: top }, Stop { offset: 1, color: bottom } ]
  }
}
function createGrayVGrad(top: Number, bottom: Number): LinearGradient {
  createColorVGrad(
    Color.color(top, top, top), Color.color(bottom, bottom, bottom))
}
